package model;

import java.util.Collection;
import java.util.HashSet;

import model.enums.Classroom;
import util.TimeBlock;

/**
 * OfferedCourse.java Purpose: this class represents a course that is being
 * offered to students by the school
 * 
 * @author Hans Brems
 * @version 1.0 03/11/2011
 */

public class OfferedCourse implements Cloneable, Comparable<OfferedCourse>,Business  {

	private Classroom classroom;
	private Course course;
	private int numberOfPlaces;
	
	private Teacher teacher;
	private TimeBlock timeBlock;
	private int minNumberOfPlaces = 10;
	private int id;

	private OfferedCourseState offeredCourseOpenState = new OfferedCourseOpenState(this);
	private OfferedCourseState offeredCourseCanceledState = new OfferedCourseCanceledState(this);
	private OfferedCourseState offeredCourseClosedState = new OfferedCourseClosedState(this);
	private OfferedCourseState offeredCourseFullState = new OfferedCourseFullState(this);
	private OfferedCourseState state = offeredCourseOpenState;

	private Collection<Observer> mailinglist = new HashSet<Observer>();


	public OfferedCourse(){}

	/** Constructs a new offered course object
	 * 
	 *   in coursecode integer,
    in classroom integer,
    in teachercode varchar(25),
    in numberofplaces integer,
    in day varchar(25),
    in starthour integer,
    in startminutes integer,
    in duration integer,
    in state varchar(25)
	 *  
	 *  */
	public OfferedCourse(int id,Course course,Classroom classroom,Teacher teacher,  int numberOfPlaces, TimeBlock timeBlock) {
		this.classroom = classroom;
		this.course = course;
		this.numberOfPlaces = numberOfPlaces;
		this.teacher = teacher;
		this.timeBlock = timeBlock;
		this.id = id;

	}

	

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	/** Returns the classroom in which the course is held **/
	public Classroom getClassroom() {
		return classroom;
	}

	/**
	 * Sets the classroom in which the course is held
	 * 
	 * @throws Exception
	 **/
	public void setClassroom(Classroom classroom) throws Exception {
		if (classroom != Classroom.UNASSIGNED) {
			this.classroom = classroom;
		} else {
			throw new Exception("Unassigned isn't a valid value for classroom.");
		}
	}

	/** Returns the course which is being offered **/
	public Course getCourse() {
		return course;
	}

	/** Sets the course which is being offered **/
	public void setCourse(Course course) {
		this.course = course;
	}

	/**
	 * Returns the maximum number of students that can follow the course at one
	 * time
	 **/
	public int getNumberOfPlaces() {
		return numberOfPlaces;
	}

	/**
	 * Sets the maximum number of students that can follow the course at one
	 * time
	 **/
	public void setNumberOfPlaces(int numberOfPlaces) {
		this.numberOfPlaces = numberOfPlaces;
	}


	

	/** Returns the teacher that is teaching the course **/
	public Teacher getTeacher() {
		return this.teacher;
	}

	/** Sets the teacher that is teaching the course **/
	public void setTeacher(Teacher teacher) {
		this.teacher = teacher;
	}

	/** Returns the time block in which the course is scheduled **/
	public TimeBlock getTimeBlock() {
		return this.timeBlock;
	}

	/** Sets the time block in which the course is scheduled **/
	public void setTimeBlock(TimeBlock timeBlock) {
		this.timeBlock = timeBlock;
	}

	/** Checks for equality with another object **/
	@Override
	public boolean equals(Object object) {

		OfferedCourse otherOfferedCourse;

		// Check for same reference
		if (this == object) {
			return true;
		}

		// Check if object type is equal
		if (object == null || object.getClass() != this.getClass()) {
			return false;
		}

		// Cast object to correct class
		otherOfferedCourse = (OfferedCourse) object;

		// Check if object properties are equal
		return otherOfferedCourse.getClassroom().equals(this.classroom)
				&& otherOfferedCourse.getNumberOfPlaces() == this.numberOfPlaces
				&&  otherOfferedCourse.getTimeBlock().equals(this.timeBlock);
	}

	/** Returns a string representation of the object **/
	@Override
	public String toString() {
		return String.format("%s (%s)", this.course.getName(), this.classroom);
		// return this.course.getName();
	}



	/** Compares the object to another object **/
	public int compareTo(OfferedCourse offeredCourse) {
		return 0;
	}



	public int getMinNumberOfPlaces() {
		return minNumberOfPlaces;
	}

	public void setMinNumberOfPlaces(int minNumberOfPlaces) {
		this.minNumberOfPlaces = minNumberOfPlaces;
	}

	public boolean registerStudent(Registration registration) throws Exception {
		return state.registerStudent(registration);

	}

	public void unregisterStudent(Registration registration) throws Exception {
		state.unregisterStudent(registration);

	}

	public void closeRegistration() throws Exception {
		state.closeRegistration();

	}

	public void cancelOfferedCourse() throws Exception {
		state.cancelOfferedCourse();

	}

	public OfferedCourseState getOfferedCourseOpenState() {
		return offeredCourseOpenState;
	}

	public OfferedCourseState getOfferedCourseCanceledState() {
		return offeredCourseCanceledState;
	}

	public OfferedCourseState getOfferedCourseClosedState() {
		return offeredCourseClosedState;
	}

	public OfferedCourseState getOfferedCourseFullState() {
		return offeredCourseFullState;
	}

	public OfferedCourseState getState() {
		return state;
	}

	public void setState(OfferedCourseState state) {
		this.state = state;

		stateChanged(state.toString());
	}

	public void registerForCourseEmail(Observer observer) {
		if (state.toString().equals(model.enums.OfferedCourseState.OPEN.toString()) || state.toString().equals(model.enums.OfferedCourseState.FULL.toString())) {
			mailinglist.add(observer);

		}
	}

	public void unRegisterForCourseEmail(Observer observer) {
		mailinglist.remove(observer);
	}

	public void stateChanged(String stateString) {
		String message = null;
		if (stateString.equals(model.enums.OfferedCourseState.CANCELED.toString())) {
			message = "offeredcourse.course.canceled";
		} else if (stateString.equals(model.enums.OfferedCourseState.CLOSED.toString())) {
			message = "offeredcourse.course.closed";
		}
		if (message != null) {
			for (Observer observer : mailinglist) {
				observer.sendEmail(message);
			}
		}
	}

}